package com.css.fxfzypg.modules.earthquakedisasterloss.service.impl;

import com.css.fxfzypg.base.response.RestResponse;
import com.css.fxfzypg.modules.SettingSeismic.entity.SeismicIntensityRelation;
import com.css.fxfzypg.modules.SettingSeismic.entity.SettingSeismicDetails;
import com.css.fxfzypg.modules.SettingSeismic.service.IntensityRelationService;
import com.css.fxfzypg.modules.SettingSeismic.service.SettingSeismicService;
import com.css.fxfzypg.modules.earthquakedisasterloss.entity.SeismicInfluenceflyPbe;
import com.css.fxfzypg.modules.earthquakedisasterloss.entity.SettingSeismicInfluenceflied;
import com.css.fxfzypg.modules.earthquakedisasterloss.repository.SettingSeismicInfluencefliedRepository;
import com.css.fxfzypg.modules.earthquakedisasterloss.service.CountEqIntensityService;
import com.css.fxfzypg.modules.maps.service.SetEarthquakeMapService;
import com.css.fxfzypg.modules.maps.service.TaskRegionMapService;
import com.css.fxfzypg.modules.model.entity.IntensityAttenuation;
import com.css.fxfzypg.modules.model.service.CasualtyService;
import com.css.fxfzypg.modules.model.service.IntensityAttenuationService;
import com.css.fxfzypg.modules.preAssessResult.service.PreAssessResultService;
import com.css.fxfzypg.modules.resultupload.service.ResultTotalService;
import com.css.fxfzypg.util.*;
import com.css.fxfzypg.zcpt.sys.entity.SUser;
import com.css.fxfzypg.zcpt.sys.service.SUserService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @Description: fxfzypg
 * @Author: lhl
 * @CreateDate: 2022/10/13 9:51
 */
@Service
public class CountEqIntensityServiceImpl implements CountEqIntensityService {

    @Resource
    IntensityAttenuationService intensityAttenuationService;

    @Resource
    IntensityRelationService intensityRelationService;

    @Resource
    SettingSeismicService settingSeismicService;
    @Resource
    SUserService sUserService;
    @Resource
    SettingSeismicInfluencefliedRepository settingSeismicInfluencefliedRepository;
    @Resource
    SetEarthquakeMapService setEarthquakeMapService;
    @Resource
    ResultTotalService resultTotalService;

    @Resource
    PreAssessResultService preAssessResultService;
    @Resource
    RedisTemplate<String, String> redisTemplate;
    @Resource
    CasualtyService casualtyService;
    @Resource
    TaskRegionMapService taskRegionMapService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResponse countEqIntensity(String taskId, String modelId,String range) {
        RestResponse restResponse= null;
        Long start = System.currentTimeMillis();
        //地震烈度衰减关系模型的id
        IntensityAttenuation modelById = intensityAttenuationService.getModelById(modelId);
        try {
            if (PlatformObjectUtils.isNotEmpty(redisTemplate.opsForValue().get(taskId))) {
                return RestResponse.fail("该任务的正在被其他人计算，请稍后再操作！！！");
            }
            redisTemplate.opsForValue().set(taskId, "2-1");
            String userId = PlatformSessionUtils.getUserId();
            String user = sUserService.getSUser(userId);
            SUser sUser = CreateGson.createGson().fromJson(user, SUser.class);

            //删除与任务关联的影响场
//            Integer count = settingSeismicInfluencefliedRepository.findCountByTaskId(taskId);
            resultTotalService.deleteRange(taskId);
            intensityRelationService.deleteSipByTaskId(taskId);
            preAssessResultService.deleteSeiCapdistribution(taskId);//删除抗震能力分布
            casualtyService.deleteDataPbeIntStrAreaByTaskId(taskId);//删除各烈度下建筑物破坏
            intensityRelationService.deleteSsiByTaskId(taskId);
//            if(count != 0) {
//            }
            SeismicIntensityRelation byTaskId = intensityRelationService.getByTaskId(taskId);
            if (PlatformObjectUtils.isEmpty(byTaskId)) {
                byTaskId = new SeismicIntensityRelation();
                byTaskId.setTaskId(taskId);
                byTaskId.setModel1Id(modelId);
                byTaskId.setModel1Type("1");
                byTaskId.setButton1_status1("1");
                byTaskId.setButton2_status1("0");
                byTaskId.setButton2_status2("0");
                byTaskId.setButton2_status3("0");
                byTaskId.setButton3_status1("0");
                byTaskId.setButton3_status2("0");
                byTaskId.setButton4_status1("0");
                byTaskId.setButton4_status2("0");
                byTaskId.setButton5_status1("0");
                byTaskId.setButton6_status1("0");
                byTaskId.setButton7_status1("0");
                byTaskId.setButton8_status1("0");
                byTaskId.setButton8_status2("0");
                byTaskId.setButton8_status3("0");
                byTaskId.setButton9_status1("0");
                intensityRelationService.saveSeismicIntensityRelation(byTaskId);
            } else {
                byTaskId.setExtends1("0");
                byTaskId.setExtends2("0");
                byTaskId.setModel1Id(modelId);
                byTaskId.setModel1Type("1");
                byTaskId.setButton1_status1("1");
                byTaskId.setButton2_status1("0");
                byTaskId.setButton2_status2("0");
                byTaskId.setButton2_status3("0");
                byTaskId.setButton3_status1("0");
                byTaskId.setButton3_status2("0");
                byTaskId.setButton4_status1("0");
                byTaskId.setButton4_status2("0");
                byTaskId.setButton5_status1("0");
                byTaskId.setButton6_status1("0");
                byTaskId.setButton7_status1("0");
                byTaskId.setButton8_status1("0");
                byTaskId.setButton8_status2("0");
                byTaskId.setButton8_status3("0");
                byTaskId.setButton9_status1("0");
                intensityRelationService.updateSeismicIntensityRelation(byTaskId);
            }
            //任务的设定地震
            List<SettingSeismicDetails> settingSeismicDetailsByTaskId = settingSeismicService.getSettingSeismicDetailsByTaskId(taskId);

            //地震烈度衰减关系模型
            BigDecimal long_ratio1 = modelById.getLongRatio1();
            BigDecimal long_ratio2 = modelById.getLongRatio2();
            BigDecimal long_ratio3 = modelById.getLongRatio3();
            BigDecimal long_ratio4 = modelById.getLongRatio4();
            String long_symbol = modelById.getLongSymbol();
            BigDecimal short_ratio1 = modelById.getShortRatio1();
            BigDecimal short_ratio2 = modelById.getShortRatio2();
            BigDecimal short_ratio3 = modelById.getShortRatio3();
            BigDecimal short_ratio4 = modelById.getShortRatio4();
            String short_symbol = modelById.getShortSymbol();

            BigDecimal formula_ratio1 = modelById.getFormulaRatio1();
            BigDecimal formula_ratio2 = modelById.getFormulaRatio1();
            //长短轴比例
            BigDecimal scale2 = modelById.getScale();

            // List<SettingSeismicDetails> list = new ArrayList<>();

            boolean isNa = false;
            BigDecimal longX = BigDecimal.ZERO;
            BigDecimal shortY = BigDecimal.ZERO;

            List<SettingSeismicInfluenceflied> influencefliedList = new ArrayList<>();
            List<SeismicInfluenceflyPbe> seismicInfluenceflyPbeList = new ArrayList<>();
            //烈度,遍历烈度
            for (SettingSeismicDetails settingSeismicDetails : settingSeismicDetailsByTaskId) {
                BigDecimal M = settingSeismicDetails.getEarthquakeLevel(); //震级

                isNa = true;
                for (int I = 10; I > 5; I--) {
                    SettingSeismicInfluenceflied influenceflied = new SettingSeismicInfluenceflied();
                    influenceflied.setEarthquakeLevel(M);
                    influenceflied.setDzIntensity(String.valueOf(I));

                    //长轴：Ia=4.9024+1.3485M-3.9738Lg(Ra+13)
                    //式中，Ia、Ib分别为长、短轴烈度，M为震级，Ra、Rb分别为烈度为I时长、短半轴的长度
                    //根据公式计算得到Ra、Rb，如果值为负数，则舍掉，为正的则留下

                    BigDecimal Ra = BigDecimal.ZERO;//烈度为Ia时长半轴的长度
                    double a = (long_ratio1.add(long_ratio2.multiply(M)).subtract(BigDecimal.valueOf(I)))
                            .divide(long_ratio3, 8, RoundingMode.UP).doubleValue();
                    if ("ln".equals(long_symbol)) {
                        Ra = BigDecimal.valueOf(Math.pow(Math.E, a)).subtract(long_ratio4);
                    } else if ("lg".equals(long_symbol)) {
                        Ra = BigDecimal.valueOf(Math.pow(10, a)).subtract(long_ratio4);
                    }
                    if (scale2.compareTo(BigDecimal.ZERO) > 0 && M.compareTo(BigDecimal.valueOf(7)) > -1) {
                        // 当使用破裂尺度公式且震级大于等于7.0级时，使用破裂尺度公式计算出长轴长度，根据长短轴比例计算出短轴长度。
                        influenceflied.setDataSource("2");

                        //M=5.08+1.16*lg(SRL)
                        //M为震级,SRL为破裂尺度
                        //根据公式计算得到SRL
                        BigDecimal SRL = BigDecimal.valueOf(Math.pow(10, formula_ratio1.subtract(M)
                                .divide(formula_ratio2, 8, RoundingMode.UP).doubleValue()));

                        //最终的长轴长度=衰减关系计算的长轴+破裂尺度
                        //最终的长轴长度=Ra*2+SRL
                        //Ra为烈度为Ia时长半轴的长度,SRL为破裂尺度
                        BigDecimal finalRa = Ra.multiply(BigDecimal.valueOf(2)).add(SRL);

                        //最终的短轴长度
                        BigDecimal finalRb = finalRa.divide(scale2, 2, RoundingMode.HALF_UP);

                        if (finalRa.compareTo(BigDecimal.ZERO) < 0) {
                            //finalRa为负数
                            continue;
                        }
                        if (finalRb.compareTo(BigDecimal.ZERO) < 0) {
                            //finalRb为负数
                            continue;
                        }
                        finalRa = finalRa.setScale(1, RoundingMode.HALF_UP);//长轴长度
                        finalRb = finalRb.setScale(1, RoundingMode.HALF_UP);//短轴长度
                        influenceflied.setLongX(finalRa);
                        influenceflied.setShortY(finalRb);
                    } else {
                        // 地震影响场可以使用烈度衰减模型进行模拟，当震级小于7.0级时使用椭圆衰减模型，
                        influenceflied.setDataSource("1");

                        // 短轴：Ib=4.3517+ 1.2192M-3.7429Lg(Rb+6)
                        //式中，Ia、Ib分别为长、短轴烈度，M为震级，Ra、Rb分别为烈度为I时长、短半轴的长度
                        //根据公式计算得到Ra、Rb，如果值为负数，则舍掉，为正的则留下

                        BigDecimal Rb = BigDecimal.ZERO;//烈度为Ib时短半轴的长度
                        double b = (short_ratio1.add(short_ratio2.multiply(M)).subtract(BigDecimal.valueOf(I))).divide(short_ratio3, 8, RoundingMode.UP).doubleValue();
                        if ("lg".equals(short_symbol)) {
                            Rb = BigDecimal.valueOf(Math.pow(10, b)).subtract(short_ratio4);
                        } else if ("ln".equals(short_symbol)) {
                            Rb = BigDecimal.valueOf(Math.pow(Math.E, b)).subtract(short_ratio4);
                        }
                        if (Ra.compareTo(BigDecimal.ZERO) < 0) {
                            //Ra为负数
                            continue;
                        }
                        if (Rb.compareTo(BigDecimal.ZERO) < 0) {
                            //Rb为负数
                            continue;
                        }
                        Ra = Ra.multiply(BigDecimal.valueOf(2)).setScale(1, RoundingMode.HALF_UP);//长轴长度
                        Rb = Rb.multiply(BigDecimal.valueOf(2)).setScale(1, RoundingMode.HALF_UP);//短轴长度
                        influenceflied.setLongX(Ra);
                        influenceflied.setShortY(Rb);
                    }
                    influenceflied.setUuid(UUIDGenerator.getUUID());
                    influenceflied.setSourceEarthquakeId(settingSeismicDetails.getId());

                    String influenceEllipse = null;
                    if (!isNa) {
                        //环
                        influenceEllipse = setEarthquakeMapService.createInfluenceEllipse(settingSeismicDetails.getLongitude().toString(),
                                settingSeismicDetails.getLatitude().toString(), influenceflied.getLongX().toString(),
                                influenceflied.getShortY().toString(),
                                String.valueOf(settingSeismicDetails.getAngle()), longX.toString(), shortY.toString());
                    } else {
                        //椭圆
                        influenceEllipse = setEarthquakeMapService.createInfluenceEllipse(settingSeismicDetails.getLongitude().toString(),
                                settingSeismicDetails.getLatitude().toString(), influenceflied.getLongX().toString(),
                                influenceflied.getShortY().toString(),
                                String.valueOf(settingSeismicDetails.getAngle()), null, null);
                    }
                    isNa = false;
                    longX = influenceflied.getLongX();
                    shortY = influenceflied.getShortY();
                    influenceflied.setGeom(influenceEllipse);
                    //处理空间数据，判断存在自相交则获取修复后的空间数据，否则返回原空间数据wkt
                    //String geomText = taskRegionMapService.getGeomValidWkt(influenceEllipse);
                    //influenceflied.setGeom("ST_GeometryFromText('" + geomText + "',4490)");

                    influenceflied.setTaskId(taskId);
                    influenceflied.setAssessmentUserId(userId);
                    influenceflied.setAssessmentUserDept(sUser.getOrgId());
                    influenceflied.setAssessmentTime(PlatformDateUtils.getCurrentTimestamp());

                    influencefliedList.add(influenceflied);
                    //settingSeismicInfluencefliedRepository.saveSettingSeismicInfluenceflied(influenceflied);
                    if (I == 6) {
                        SeismicInfluenceflyPbe seismicInfluenceflyPbe = new SeismicInfluenceflyPbe();
                        seismicInfluenceflyPbe.setUuid(UUIDGenerator.getUUID());
                        seismicInfluenceflyPbe.setDetailsId(settingSeismicDetails.getId());
                        seismicInfluenceflyPbe.setInfluenceflyId(influenceflied.getUuid());

                        influenceEllipse = setEarthquakeMapService.createInfluenceEllipse(settingSeismicDetails.getLongitude().toString(),
                                settingSeismicDetails.getLatitude().toString(), influenceflied.getLongX().toString(),
                                influenceflied.getShortY().toString(),
                                String.valueOf(settingSeismicDetails.getAngle()), null, null);

                        seismicInfluenceflyPbe.setGeom(influenceEllipse);
                        seismicInfluenceflyPbe.setTaskId(taskId);
                        seismicInfluenceflyPbeList.add(seismicInfluenceflyPbe);
                        //settingSeismicInfluencefliedRepository.saveSeismicInfluenceflyPbe(seismicInfluenceflyPbe);
                        //存储每个点最外圈的地震影响场的点详情的数据
                        // list.add(settingSeismicDetails);
                    }
                }
            }
            if (influencefliedList.size() > 0){
                //生成此taskId分区表
                settingSeismicInfluencefliedRepository.createInfluencefliedTable(taskId);
                //批量插入
                System.out.println(influencefliedList.size());
                settingSeismicInfluencefliedRepository.saveSettingSeismicInfluencefliedList(influencefliedList);
                System.out.println("插入完成");
            }
            if (seismicInfluenceflyPbeList.size() > 0){
                //批量插入
                System.out.println(seismicInfluenceflyPbeList.size());
                settingSeismicInfluencefliedRepository.saveSeismicInfluenceflyPbeLisst(seismicInfluenceflyPbeList);
                System.out.println("插入完成");
            }
            resultTotalService.saveRange(range,taskId);
            resultTotalService.saveYpgResult(taskId,range);
            System.out.println("生成影响场时间" + (System.currentTimeMillis() - start) / 1000);
            return ResponseCreator.createSuccessResponse(modelById, "保存成功！");
        } catch (Exception e) {
            e.printStackTrace();
            restResponse= RestResponse.fail("生成地震影响场失败！");
            return  restResponse;
        } finally {
            redisTemplate.delete(taskId);
            if (restResponse != null) {
                if (restResponse.getCode() != 200) {
                    //事务手动回滚
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                }
            }
        }
    }

    @Override
    public RestResponse getRangeByTaskId(String taskId) {
       return RestResponse.succeed(resultTotalService.getRangeByTaskId(taskId));
    }

    @Override
    public RestResponse deleteDateByTaskId(String taskId) {
        RestResponse restResponse= null;
        try {
            if (PlatformObjectUtils.isNotEmpty(redisTemplate.opsForValue().get(taskId))) {
                return RestResponse.fail("该任务的正在被其他人计算，请稍后再操作！！！");
            }
            redisTemplate.opsForValue().set(taskId, "2-1");
            //删除与任务关联的影响场
            Integer count = settingSeismicInfluencefliedRepository.findCountByTaskId(taskId);
            if(count!=0){
                intensityRelationService.deleteSsiByTaskId(taskId);
                intensityRelationService.deleteSipByTaskId(taskId);
                preAssessResultService.deleteSeiCapdistribution(taskId);//删除抗震能力分布
                casualtyService.deleteDataPbeIntStrAreaByTaskId(taskId);//删除各烈度下建筑物破坏
            }
            SeismicIntensityRelation byTaskId = intensityRelationService.getByTaskId(taskId);
            if (PlatformObjectUtils.isNotEmpty(byTaskId)){
                intensityRelationService.updateSeismicIntensityRelationByTaskId(byTaskId.getId());
            }
            return restResponse=RestResponse.succeed("删除影响场数据完成");
        }catch (Exception e) {
            e.printStackTrace();
            restResponse= RestResponse.fail("删除影响场数据失败！");
            return  restResponse;
        } finally {
            redisTemplate.delete(taskId);
            if (restResponse != null) {
                if (restResponse.getCode() != 200) {
                    //事务手动回滚
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                }
            }
        }
    }
}
